package com.chinaums.fsp.sdk.request;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.entity.ContentType;
import org.xiajinsuo.avro.specific.BaseException;
import org.xiajinsuo.avro.specific.SpecificRecordBase;
import org.xiajinsuo.avro.specific.SpecificRecordUtils;

import com.alibaba.fastjson.JSON;
import com.chinaums.fsp.base.pgt.TransType;
import com.chinaums.fsp.channel.base.HttpUtils;
import com.chinaums.fsp.exception.CertLoadException;
import com.chinaums.fsp.exception.NotFoundException;
import com.chinaums.fsp.sdk.base.RequestData;
import com.chinaums.fsp.sdk.base.SignType;
import com.chinaums.fsp.sdk.ca.CaGenerator;
import com.chinaums.fsp.sdk.pgt.params.CallBackRequest;
import com.chinaums.fsp.sdk.pgt.params.OrganizationAuditRequest;
import com.chinaums.fsp.sdk.sec.SignFactory;
import com.chinaums.fsp.sdk.sec.impl.AbstractDataEncrypt;
import com.chinaums.fsp.sdk.sec.impl.RSADataEncrypt;
import com.chinaums.fsp.trans.exception.SignException;
import com.chinaums.fsp.util.StringUtils;

import junit.framework.TestCase;

public class PgtCallBackTest extends TestCase {
	
	private final String DEFAULT_CHARSET = "UTF-8";
	private final String SIGN_NAME = "sign";
	
	protected Certificate	serverCertificate;
	protected KeyStore		clientKeyStore;
	protected final String	KEYSTORE_PASSWORD	= "123456";
	protected final String	PRIVATEKEY_PASSWORD	= "123456";
	
	
	public void testCallBack() throws Exception{
		String result = "";
//		String url = "http://apitst.qingzhongfu.com:8002/qzf/api/ms/callback";
		String url = "";
		
		OrganizationAuditRequest request = OrganizationAuditRequest.newBuilder()
				.setAuditInfo("123123")
				.setAuditStatus(1)
				.setAuditTime(StringUtils.formatTime(new Date()))
				.setBusinessLicense("123123123")
				.setWalletNo("123123123")
				.setFullName("123123123")
				.build();

		RequestData.Builder builder = RequestData.newBuilder();
		
		String time = StringUtils.formatTime(new Date());
		String nanoTime = System.nanoTime() + "";
		builder.setAppId("801000000000006F45MJL44")
				.setClientTransId(time + nanoTime.substring(nanoTime.length() - 6))
				.setSignType(SignType.RSA)
				.setTransTimestamp(System.currentTimeMillis())
				.setTransType(TransType.CALLBACK_ORGANIZATION_AUDIT.getTransCode())
				;
		
		RequestData data = (RequestData) this
				.createRequest(builder, request);
		System.out.println(data);
		//验签
		 Map maps = (Map)JSON.parse(data.toString());  
		 System.out.println(maps);
		AbstractDataEncrypt decrypt =this.getClientDataDecrypt(data,CallBackRequest.class);
		this.validateSignAndDecrypt(data,decrypt,maps);
//		result = HttpUtils.post(url, data, ContentType.create(ContentType.APPLICATION_JSON.getMimeType(), "utf-8"));
		
	}
	protected void validateSignAndDecrypt(RequestData request, AbstractDataEncrypt decrypt, Map<Object, Object> parameters) throws BaseException {
		
		Map<String, String> map = new HashMap<String, String>();
		for (Object key : parameters.keySet()) {
			Object value = parameters.get(key);
			if (null != value) {
				map.put(key.toString(), value.toString());
			}
		}
		map.remove("sign");
		byte[] sortData = decrypt.getSortString(map);
		
		if (!decrypt.verify(sortData, request.getSign())) {
			throw new SignException();
		}
		
		RSADataEncrypt rd = (RSADataEncrypt)decrypt;
		SpecificRecordBase srb = SpecificRecordUtils.newInstance(rd.getRecordClass());
		SpecificRecordUtils.parse(srb, parameters);
		System.out.println(srb);
	}
	
	protected PublicKey getPublicKey() throws Exception {
		try {
			Certificate cert = CaGenerator.getCertificate(this.getInputStream("/certs/fsp_client.cer"));
			return cert.getPublicKey();
		} catch (KeyStoreException e) {
			throw new CertLoadException("解析公钥失败");
		}
	}
	/**
	 * 创建签名
	 * 
	 * @param builder
	 * @param data
	 * @return
	 */
	public Object createRequest(RequestData.Builder builder,
			SpecificRecordBase data) {
		try {
			AbstractDataEncrypt encrypt = getServerDataEncrypt(builder
					.getSignType());
			RequestData reqData = null;
			byte[] sortData = null;
			switch (builder.getSignType()) {
			case RSA:
			case RSA_DATA_ENCRYPT:
				if (null != data) {
					builder.setData(encrypt.encrypt(data));
				}
				reqData = builder.setSign("").build();
				sortData = encrypt.getSortString(reqData);
				String str = encrypt
						.sign(new String(sortData, DEFAULT_CHARSET));
				return RequestData.newBuilder(reqData).setSign(str).build();
			case RSA_SINGLE_SIGN:
				reqData = builder.setSign("").build();
				Map<String, String> respMap = new HashMap<String, String>();
				respMap.putAll(SpecificRecordUtils.toMap(reqData));
				if (null != data) {
					respMap.putAll(SpecificRecordUtils.toMap(data));
				}
				respMap.remove(SIGN_NAME);
				sortData = encrypt.getSortString(respMap);
				String sign = encrypt
						.sign(new String(sortData, DEFAULT_CHARSET));
				respMap.put(SIGN_NAME, sign);
				return respMap;
			default:
				throw new RuntimeException("不支持的签名类型");
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 获取客户端解密对像
	 * @return
	 * @throws Exception 
	 */
	protected AbstractDataEncrypt getClientDataDecrypt(RequestData request, Class<? extends SpecificRecordBase> dataClass) throws Exception {
		return SignFactory.createDataEncrypt(this.getPublicKey().getEncoded(), dataClass, request.getSignType());
	}
	/**
	 * 获取服务端加密对像
	 * 
	 * @return
	 */
	private AbstractDataEncrypt getServerDataEncrypt(SignType signType)
			throws Exception {
		return SignFactory.createDataEncrypt(getPrivateKey(), signType);
	}

	/**
	 * 获取私钥
	 * 
	 * @return
	 * @throws Exception 
	 * @throws KeyStoreException 
	 */
	private PrivateKey getPrivateKey() throws KeyStoreException, Exception {
		this.serverCertificate = CaGenerator
				.getCertificate(this.getInputStream("/certs/fsp_server.cer"));
		this.clientKeyStore = CaGenerator.getKeyStore(
				CaGenerator.KEYSTORE_PKCS12,
				this.getInputStream("/certs/fsp_client.pfx"),
				KEYSTORE_PASSWORD.toCharArray());
		
		return (PrivateKey) CaGenerator.getPrivateKey(clientKeyStore, PRIVATEKEY_PASSWORD);
	}
	
	private InputStream getInputStream(String path) throws Exception {
		InputStream in = BaseRequest.class.getResourceAsStream(path);
		if (null == in) {
			throw new NotFoundException("未找到" + path + "证书");
		}
		return in;
	}
}
